/******************************************************************************
 *                  Shanghai ChipON Micro-Electronic Co.,Ltd                  *
 ******************************************************************************
 *  $File Name$       : main.c                                         	      *
 *  $Author$          : ChipON AE/FAE Group                                   *
 *  $Data$            : 2021-07-8                                             *
 *  $Hard Version     : KF32A156-MINI-EVB_V1.2                                *
 *  $Description$     : This example demonstrates how go to STOP1 sleep mode, *
 * 						and wakeup source									  *
 * 						-Timer0 in STOP1 mode 								  *
 * 						-RTC beat Interrupt in STOP1 mode					  *
 * 						-WKUP pins in STOP1 mode							  *
 ******************************************************************************
 *  Copyright (C) by Shanghai ChipON Micro-Electronic Co.,Ltd                 *
 *  All rights reserved.                                                      *
 *                                                                            *
 *  This software is copyright protected and proprietary to                    *
 *  Shanghai ChipON Micro-Electronic Co.,Ltd.                                 *
 ******************************************************************************
 *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  *
 *                     		REVISON HISTORY                               	  *
 *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  *
 *  Data       Version  Author        Description                             *
 *  ~~~~~~~~~~ ~~~~~~~~ ~~~~~~~~~~~~  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  *
 *  2021-07-08 00.02.00 FAE Group     Version 2.0 update                      *
 *                                                                            *
 *                                                                            *
 *****************************************************************************/

/******************************************************************************
**                      		Include Files                                **
******************************************************************************/
#include "system_init.h"
#include "Usart.h"
/******************************************************************************
**                      	Private variables                                **
******************************************************************************/
static volatile uint32_t TimingDelay=0;

/*******************************************************************************
**                     		   Global Functions 		             	      **
*******************************************************************************/
/**
 *  @brief :Initialize the LED GPIO ports
 * 			PC0	------------- UserKey
 * 			PC6 ------------ -LED2
 * 			PC5 ------------- LED3
 * 			PC2 --------------LED4
 *  @param in :None
 *  @param out :None 
 *  @retval :None
 */
void BoardGpioInit(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	
	/* Configure PC6 LED2 output */
	GPIO_InitStructure.m_Mode = GPIO_MODE_OUT;
	GPIO_InitStructure.m_OpenDrain = GPIO_POD_PP;
	GPIO_InitStructure.m_PullDown = GPIO_NOPULL;
	GPIO_InitStructure.m_PullUp = GPIO_NOPULL;
	GPIO_InitStructure.m_Speed = GPIO_LOW_SPEED;
	GPIO_InitStructure.m_Pin = GPIO_PIN_MASK_6;
	GPIO_Configuration(GPIOC_SFR , &GPIO_InitStructure);
	/* Configure PC2 LED4 output */
	GPIO_InitStructure.m_Pin = GPIO_PIN_MASK_2;
	GPIO_Configuration(GPIOC_SFR , &GPIO_InitStructure);
	/* Configure PC5 LED3 output */
	GPIO_InitStructure.m_Pin = GPIO_PIN_MASK_5;
	GPIO_Configuration(GPIOC_SFR , &GPIO_InitStructure);
	/* Configure PC0 user key input */
	GPIO_InitStructure.m_Mode = GPIO_MODE_IN;
	GPIO_InitStructure.m_Pin = GPIO_PIN_MASK_0;
	GPIO_Configuration(GPIOC_SFR , &GPIO_InitStructure);
}

/**
 *  @brief :Config the BKP area is enable, BKP register and data can be write and read
 *  @param in :None
 *  @param out :None
 *  @retval :None
 */
void BKP_WriteReadEnable(void)
{
	/* The backup domain register allows reading and writing */
	SFR_SET_BIT_ASM(OSC_CTL0, OSC_CTL0_PMWREN_POS);
	/* Backup domain exits reset mode */
	SFR_SET_BIT_ASM(PM_CTL0, PM_CTL0_BKPREGCLR_POS);
	/* The backup area allows reading and writing */
	SFR_SET_BIT_ASM(PM_CTL0, PM_CTL0_BKPWR_POS);
}

/**
 *  @brief : Initialize Timer0 and configure it can be runnning in STOP1 mode
 * 			 'BKP_WriteReadEnable' function called must be first!!!
 *  @param in :None
 *  @param out :None
 *  @retval :None
 */
void Timer0LowPowerInit(void)
{
	GPTIM_InitTypeDef  GPTIM_InitStructure;
	/* Disable the INTLF as the clock of CCP0, and reset the Timer0 */
	PM_CCP0CLKLPEN_Enable(FALSE);
	PM_CCP0LPEN_ENABLE(FALSE);
	GPTIM_Reset(T0_SFR);
	/* Timer0 configured as follow:
		- InputClock = INTLF = 32K
		- Prescal = 31
		- Period = 1000
	 */
	GPTIM_InitStructure.m_Clock = GPTIM_T0_INTLF;
	GPTIM_InitStructure.m_Counter = 0;
	GPTIM_InitStructure.m_CounterMode = GPTIM_COUNT_UP_OF;
	GPTIM_InitStructure.m_MasterSlaveSync = FALSE;
	GPTIM_InitStructure.m_Period = 1000;
	GPTIM_InitStructure.m_Prescaler = 31;
	GPTIM_InitStructure.m_SlaveMode = GPTIM_SLAVE_FORBIDDEN_MODE;
	GPTIM_InitStructure.m_WorkMode = GPTIM_TIMER_MODE;
	GPTIM_Configuration(T0_SFR, &GPTIM_InitStructure);
	/* Enable Timer0, and enable overflow interrupt */
	GPTIM_Cmd(T0_SFR, ENABLE);
	INT_Interrupt_Enable(INT_T0,TRUE);
	GPTIM_Clear_Overflow_INT_Flag(T0_SFR);
	GPTIM_Overflow_INT_Enable(T0_SFR, ENABLE);
	/* Enable Timer0 running in STOP1 mode */
	PM_Internal_Low_Frequency_Enable(TRUE);
	PM_CCP0LPEN_ENABLE(TRUE);
	PM_CCP0CLKLPEN_Enable(TRUE);
}

/**
 *  @brief :
 *  @param in :None
 *  @param out :None
 *  @retval :None
 */
void RTCLowPowerInit(void)
{
	RTC_InitTypeDef RTC_INIT;
		/*reset RTC**************************************************************/
	RTC_Reset();

	/* Set the INTLF to the RTC clock source ********************************/
	RTC_INIT.m_ClockSource = RTC_WORK_CLK_INTLF;
	/* Set RTC time format:24-hour clock ************************************/
	RTC_INIT.m_HourFormat = RTC_HOUR_FORMAT_24;
	/* Set RTC hours Initial value:20 ***************************************/
	RTC_INIT.m_TimeStruct.m_Hours = 20;
	/* Set RTC minutes Initial value:0 **************************************/
	RTC_INIT.m_TimeStruct.m_Minutes = 0;
	/* Set RTC seconds Initial value:0 **************************************/
	RTC_INIT.m_TimeStruct.m_Seconds = 0;
	/* set AM/PM.but 24-hour format don't need set AM/PM.********************/
	//	RTC_INIT.m_TimeStruct.m_AMPM = RTC_TIME_AM;
	/* Set RTC week Initial value:WEDNESDAY *********************************/
	RTC_INIT.m_DateStruct.m_WeekDay = RTC_WEEKDAY_WEDNESDAY_DEC;
	/* Set RTC year Initial value :19****************************************/
	RTC_INIT.m_DateStruct.m_Year = 19;
	/* Set RTC month Initial value: OCTOBER**********************************/
	RTC_INIT.m_DateStruct.m_Month = RTC_MONTH_OCTOBER_DEC;
	/* Set RTC date Initial value :30****************************************/
	RTC_INIT.m_DateStruct.m_Day = 30;
	/*Declare that the input parameters are not in BCD encoding format, and
	write the time and date into the register********************************/
	RTC_Configuration(RTC_TIME_FORMAT_BIN,&RTC_INIT);
}

/**
 *  @brief :
 *  @param in :None
 *  @param out :None
 *  @retval :None
 */
void RTCBeatInit(void)
{
	EINT_InitTypeDef EINT_17to19;
	RTC_Config_Mode_Enable (TRUE);
	/* Configure INT_EINT19TO17 */
    EINT_17to19.m_Rise = TRUE;
    EINT_17to19.m_Fall = FALSE;
	EINT_17to19.m_Mask = TRUE;
    EINT_17to19.m_Line = INT_EXTERNAL_INTERRUPT_17;
    INT_External_Configuration(&EINT_17to19);


	RTC_Time_Tick_Config(RTC_TIME_TICK_DIV_1);
	RTC_Clear_Time_Tick_INT_Flag();
	RTC_Time_Tick_INT_Enable (TRUE);

	/* Enable RTC running in STOP1 mode */
	PM_Internal_Low_Frequency_Enable(TRUE);
	PM_RTC_Reset_Control(TRUE);
	PM_RTC_Work_Stop_INTLF_Enable(TRUE);
     /*enable rtc seconds interrupt*/
	RTC_Enable(TRUE);
	RTC_Config_Mode_Enable (FALSE);
	INT_Clear_Interrupt_Flag(INT_EINT19TO17);
	INT_Interrupt_Enable(INT_EINT19TO17,TRUE);



}

/**
 *  @brief : Initialize the WKUP2 Pin in PC0, WKUP1~5 in this way
 * 			'BKP_WriteReadEnable' function called must be first!!!
 *  @param in :None
 *  @param out :None
 *  @retval :None
 */
void WakeupPinInit(void)
{
	if (PM_Get_Reset_Flag(PM_WAKEUP_EXTERNAL_PIN_WKP2))
	{
		PM_Clear_External_Wakeup_Pin_Flag(PM_WAKEUP_EXTERNAL_PIN_WKP2);
	}
	PM_External_Wakeup_Pin_Enable(PM_PIN_WKP2, TRUE);
	PM_External_Wakeup_Edge_Config(PM_PIN_WKP2, PM_TRIGGER_FALL_EDGE);
}

/**
 *  @brief :Set the stop1 sleep mode, and go to sleep
 *  @param in :None
 *  @param out :None
 *  @retval :None
 */
void SystemGotoStop1Mode(void)
{
//	/* Set stop1 sleep mode */
	PM_Low_Power_Mode_Config(PM_LOW_POWER_MODE_STOP_1);
	/* Go to sleep */
	asm("SLEEP");
}

/*******************************************************************************
**                     			Main Functions 		             	     	  **
*******************************************************************************/
/**
 *  @brief :Main program
 *  @param in :None
 *  @param out :None
 *  @retval :None
 */
int main()
{
	EINT_InitTypeDef EINT_17to19;
	volatile uint32_t i;
	/* System clock configuration */
	SystemInit(SYSCLK_FREQ);
	/* Setup SysTick Timer as delay funct*/
	systick_delay_init(SYSCLK_FREQ);
	/* Initialize the LED IOs */
	BoardGpioInit();
	/* Set the BKP area is enable */
	BKP_WriteReadEnable();
	Usart_Gpio_Init();
	USART_Mode_Config(USART1_SFR);
	GPIO_Set_Output_Data_Bits(GPIOC_SFR,GPIO_PIN_MASK_2|GPIO_PIN_MASK_5,RESET);
	/* If it is awakened by the RTC beat interrupt, it will enter this statement */
	if (RTC_Get_Time_Tick_INT_Flag() != RESET)
	{
		RTC_Clear_Time_Tick_INT_Flag();
		/* Turn on LED4 to represent wake-up from RTC  */
		GPIO_Set_Output_Data_Bits(GPIOC_SFR,GPIO_PIN_MASK_2,SET);
	}
	/* Query whether it is WKUP2 pin wakeup, clear WKUP2 flag, and light the LED2 */
	if (PM_Get_Reset_Flag(PM_WAKEUP_EXTERNAL_PIN_WKP2))
	{
		PM_Clear_External_Wakeup_Pin_Flag(PM_WAKEUP_EXTERNAL_PIN_WKP2);
		/* Turn on LED3 to represent wake-up from RTC  */
		GPIO_Toggle_Output_Data_Config(GPIOC_SFR, GPIO_PIN_MASK_5);
		GPIO_Set_Output_Data_Bits(GPIOC_SFR,GPIO_PIN_MASK_5,SET);
	}
	PM_External_Wakeup_Pin_Enable(PM_PIN_WKP2, FALSE);
	/* Turn ON/OFF the LED2 every 200ms for 10 times, it showing power on state */
	do
	{
		GPIO_Toggle_Output_Data_Config(GPIOC_SFR, GPIO_PIN_MASK_6);
		systick_delay_ms(200);
	} while ((TimingDelay++ < 10));
	while(1)
	{
		/* Scan the user key */
		if (GPIO_Read_Input_Data_Bit(GPIOC_SFR, GPIO_PIN_MASK_0) == Bit_RESET)
		{
#if 0		/* Only one of RTC and Timer0 can be selected */
			/* Initialize Timer0, running in STOP1 mode */
			Timer0LowPowerInit();
#endif
#if 0

		RTCLowPowerInit();
    /* Configure and enable INT_EINT19TO17 */
		RTCBeatInit();
#endif
#if 1
			/* Initialize the WKUP2 Pin in PC0 */
			WakeupPinInit();
#endif
			/* Go to Sleep */
			SystemGotoStop1Mode();
		}
	}		
}

/**
 *  @brief : Reports the name of the source file and the source line number
 *           where the assert_param error has occurred.
 *  @param in :	file pointer to the source file name
 * 	@param in :	line assert_param error line source number
 *  @param out :None
 *  @retval :None
 */
void check_failed(uint8_t* File, uint32_t Line)
{
	/* User can add his own implementation to report the file name and line number,
		ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */

	/* Infinite loop */
	while(1)
	{
		;
	}
};
